home *** CD-ROM | disk | FTP | other *** search
/ Complete Linux / Complete Linux.iso / docs / system / mail / delivery / deliver.tz / deliver / log.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-12-07  |  8.1 KB  |  407 lines

  1. /* $Header: log.c,v 2.3 90/05/03 10:13:31 chip Exp $
  2.  *
  3.  * Deliver logging.
  4.  *
  5.  * $Log:    log.c,v $
  6.  * Revision 2.3  90/05/03  10:13:31  chip
  7.  * Print correct filename when log can't be opened.
  8.  * 
  9.  * Revision 2.2  90/03/05  17:54:53  chip
  10.  * Create log.c from various routines throughout the code.
  11.  * 
  12.  */
  13.  
  14. #include "deliver.h"
  15. #include <time.h>
  16.  
  17. /*----------------------------------------------------------------------
  18.  * Open temporary log files.
  19.  */
  20.  
  21. openlogs()
  22. {
  23. #ifdef ERRLOG
  24.     /* If we're delivering and not being verbose, keep an error log. */
  25.  
  26.     if (!dryrun && !verbose)
  27.     {
  28.         errlogfile = tempfile();
  29.         if ((errlog = ftcreate(errlogfile)) == NULL)
  30.             syserr("can't create %s", errlogfile);
  31.     }
  32. #endif
  33.  
  34. #ifdef LOG
  35.     /* If we're delivering and the log file exists, keep data for it. */
  36.  
  37.     if (!dryrun && exists(LOG))
  38.     {
  39.         logfile = tempfile();
  40.         if ((log = ftcreate(logfile)) == NULL)
  41.             syserr("can't create %s", logfile);
  42.     }
  43. #endif
  44. }
  45.  
  46. /*------------------------------------------------------------------------
  47.  * Discard temporary log files.
  48.  */
  49.  
  50. tosslogs()
  51. {
  52.     if (logfile && unlink(logfile) == -1)
  53.         (void) syserr("can't remove %s", logfile);
  54.     if (errlogfile && unlink(errlogfile) == -1)
  55.         (void) syserr("can't remove %s", logfile);
  56. }
  57.  
  58. /*----------------------------------------------------------------------
  59.  * Write a report to the log file.
  60.  */
  61.  
  62. logreport(ac, av)
  63. int     ac;
  64. char    **av;
  65. {
  66.     int     a;
  67.  
  68.     if (!log)
  69.         return;
  70.  
  71.     logstart(log);
  72.  
  73.     if (sender && *sender)
  74.         (void) fprintf(log, "sender: %s\n", sender);
  75.     if (boxdelivery)
  76.         (void) fprintf(log, "mailbox%s:", (ac > 1) ? "es" : "");
  77.     else
  78.         (void) fprintf(log, "destination%s:", (ac > 1) ? "s" : "");
  79.     for (a = 0; a < ac; ++a)
  80.         (void) fprintf(log, " \"%s\"", av[a]);
  81.     (void) fputc('\n', log);
  82.  
  83.     logstate("delivered", ST_DONE);
  84.     logstate("failed", ST_ERROR);
  85.  
  86.     logdone(log);
  87. }
  88.  
  89. /*----------------------------------------------------------------------
  90.  * Log the destinations with the given state.
  91.  * If any are found, the list is prefixed with the given description.
  92.  */
  93.  
  94. logstate(desc, state)
  95. char    *desc;
  96. DSTATE  state;
  97. {
  98.     DEST    *d;
  99.     int     dcount;
  100.  
  101.     dcount = 0;
  102.     for (d = first_dest(); d; d = next_dest(d))
  103.     {
  104.         if (d->d_state != state)
  105.             continue;
  106.  
  107.         if (++dcount == 1)
  108.             (void) fprintf(log, "%s:", desc);
  109.         (void) fprintf(log, " %s", d->d_name);
  110.         if (d->d_class == CL_MBOX)
  111.             (void) fprintf(log, ":%s", d->d_param);
  112.         else if (d->d_class == CL_PROG)
  113.             (void) fprintf(log, "|\"%s\"", d->d_param);
  114.     }
  115.     if (dcount)
  116.         (void) fputc('\n', log);
  117. }
  118.  
  119. /*----------------------------------------------------------------------
  120.  * Save contents of temporary logs in the real logfiles.
  121.  */
  122.  
  123. savelogs()
  124. {
  125.     /* If logs weren't kept, forget it. */
  126.  
  127.     if (!log && !errlog)
  128.         return;
  129.  
  130.     /* If temporary logs contain anything, append them to real logs. */
  131.  
  132.     if ((log && ftell(log) > 0)
  133.      || (errlog && ftell(errlog) > 0))
  134.     {
  135.         if (create_lockfile(LOGLOCK) == 0)
  136.         {
  137. #ifdef LOG
  138.             applog(&log, LOG);
  139. #endif
  140.             errdone();
  141. #ifdef ERRLOG
  142.             applog(&errlog, ERRLOG);
  143. #endif
  144.             (void) remove_lockfile(LOGLOCK);
  145.         }
  146.     }
  147. }
  148.  
  149. /*----------------------------------------------------------------------
  150.  * Append a temporary log file to a real logfile.
  151.  * We pass a FILE **, so that it can be set to NULL when closed;
  152.  * this is important, since errlog is used by syserr().
  153.  * Note:  The logfile is ass_u_med to be locked already!
  154.  */
  155.  
  156. applog(fpp, realfile)
  157. FILE    **fpp;
  158. char    *realfile;
  159. {
  160.     FILE    *fp = fpp ? *fpp : NULL;
  161.     int    fd, realfd;
  162.  
  163.     /* If log data weren't kept, never mind. */
  164.  
  165.     if (fp == NULL)
  166.         return;
  167.  
  168.     /* Flush buffered data. */
  169.  
  170.     (void) fflush(fp);
  171.  
  172.     /* If the file is empty, never mind. */
  173.  
  174.     if (ftell(fp) == 0)
  175.     {
  176.         (void) fclose(fp);
  177.         *fpp = NULL;
  178.         return;
  179.     }
  180.  
  181.     /* Get an fd and close the stream. */
  182.  
  183.     if ((fd = dup(fileno(fp))) == -1)
  184.     {
  185.         syserr("can't dup log fd");
  186.         (void) fclose(fp);
  187.         *fpp = NULL;
  188.         return;
  189.     }
  190.     (void) fclose(fp);
  191.     *fpp = NULL;
  192.  
  193.     /*
  194.      * Open the real logfile, creating it if necessary.
  195.      * Note that there is no race condition since the logs are locked.
  196.      */
  197.  
  198. #ifdef O_CREAT
  199.     realfd = open(realfile, O_WRONLY|O_CREAT, 0666);
  200. #else
  201.     if ((realfd = open(realfile, O_WRONLY)) == -1)
  202.         realfd = creat(realfile, 0666);
  203. #endif
  204.     if (realfd == -1)
  205.         syserr("can't open %s for writing", realfile);
  206.     else
  207.     {
  208.         /* Append the temporary log to the real log. */
  209.  
  210.         (void) lseek(fd, 0L, 0);
  211.         (void) lseek(realfd, 0L, 2);
  212.         (void) copyfd(fd, realfd);
  213.         (void) close(realfd);
  214.     }
  215.  
  216.     /* Close the temporary log. */
  217.  
  218.     (void) close(fd);
  219. }
  220.  
  221. /*----------------------------------------------------------------------
  222.  * Record any interesting information in the error log file.
  223.  */
  224.  
  225. errinfo()
  226. {
  227.     if (!errlog)
  228.         return;
  229.  
  230.     /* Log undelivered mail. */
  231.  
  232.     errundel();
  233.  
  234.     /* If any errors have been logged, record the failed header. */
  235.  
  236.     if (ftell(errlog) > 0)
  237.         errheader();
  238. }
  239.  
  240. /*----------------------------------------------------------------------
  241.  * Log undelivered mail.
  242.  *
  243.  * Note that this algorithm assumes that delivery to the MBX_UNDEL mailbox
  244.  * is always worth reporting.
  245.  */
  246.  
  247. errundel()
  248. {
  249.     DEST    *d;
  250.  
  251.     if (!errlog)
  252.         return;
  253.  
  254.     for (d = first_dest(); d; d = next_dest(d))
  255.     {
  256.         if (d->d_state == ST_DONE
  257.          && d->d_class == CL_MBOX
  258.          && strcmp(d->d_param, MBX_UNDEL) == 0)
  259.         {
  260.             CONTEXT *ct;
  261.             char    *home;
  262.  
  263.             if ((ct = name_context(d->d_name)) != NULL)
  264.                 home = ct->ct_home;
  265.             else
  266.                 home = "~";     /* should never happen */
  267.  
  268.             errstart();
  269.             (void) fprintf(errlog,
  270.                 "Undelivered mail for %s put in %s/%s\n",
  271.                 d->d_name, home, MBX_UNDEL);
  272.         }
  273.     }
  274. }
  275.  
  276. /*----------------------------------------------------------------------
  277.  * Log the message header.
  278.  */
  279.  
  280. errheader()
  281. {
  282.     FILE    *hfp;
  283.     int     hfd;
  284.  
  285.     if (!errlog)
  286.         return;
  287.  
  288.     /* Copy the failed message's header. */
  289.  
  290.     hfd = dup(tfd[T_HDR]);
  291.     hfp = (hfd < 0) ? NULL : fdopen(hfd, "r");
  292.     if (hfp == NULL)
  293.     {
  294.         (void) fprintf(errlog, "%s: can't open header file %s\n",
  295.                     progname, tfile[T_HDR]);
  296.     }
  297.     else
  298.     {
  299.         int     c, oc;
  300.  
  301.         (void) fprintf(errlog, "+ Header:\n");
  302.  
  303.         (void) fseek(hfp, 0L, 0);
  304.         oc = '\n';
  305.         while ((c = getc(hfp)) != EOF)
  306.         {
  307.             if (oc != '\n' || c != '\n')
  308.             {
  309.                 if (oc == '\n')
  310.                     (void) fputs("| ", errlog);
  311.                 (void) putc(c, errlog);
  312.             }
  313.             oc = c;
  314.         }
  315.  
  316.         (void) fclose(hfp);
  317.     }
  318. }
  319.  
  320. /*----------------------------------------------------------------------
  321.  * Record a time stamp in the error log file.
  322.  */
  323.  
  324. errstart()
  325. {
  326.     /* If we've already written a time stamp, don't do it again. */
  327.  
  328.     if (!errlog || ftell(errlog) > 0)
  329.         return;
  330.  
  331.     /* Write a time stamp and various useful info. */
  332.  
  333.     logstart(errlog);
  334.     (void) fprintf(errlog, "process %d", getpid());
  335.     if (rec_parent > 0)
  336.         (void) fprintf(errlog, ", parent %d", rec_parent);
  337.     (void) fprintf(errlog, ": %s %s\n", progname, version);
  338. }
  339.  
  340. /*----------------------------------------------------------------------
  341.  * Record the end of this process's error log entry.
  342.  */
  343.  
  344. errdone()
  345. {
  346.     /* If we never wrote to the error log file, do nothing. */
  347.  
  348.     if (!errlog || ftell(errlog) == 0)
  349.         return;
  350.  
  351.     /* Write a simple closing line for the error log entry. */
  352.  
  353.     (void) fprintf(errlog, "process %d", getpid());
  354.     if (rec_parent > 0)
  355.         (void) fprintf(errlog, ", parent %d", rec_parent);
  356.     (void) fprintf(errlog, ": exit\n");
  357.  
  358.     logdone(errlog);
  359. }
  360.  
  361. /*----------------------------------------------------------------------
  362.  * Start a log entry.
  363.  * Various useful info goes here -- especially a timestamp.
  364.  */
  365.  
  366. logstart(fp)
  367. FILE    *fp;
  368. {
  369.     struct tm *lt;
  370.     time_t  now;
  371.     static char month[12][4] = {
  372.         "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  373.         "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
  374.     };
  375.  
  376.     (void) time(&now);
  377.     lt = localtime(&now);
  378.  
  379.     (void) fputc('\n', fp);
  380.     if (rec_level)
  381.         (void) fprintf(fp, "[%d]", rec_level);
  382.     else
  383.         (void) fputs("---", fp);
  384.     (void) fputs("------------------------ ", fp);
  385.     (void) fprintf(fp, "%d %s %d, %02d:%02d:%02d %s\n",
  386.             lt->tm_mday, month[lt->tm_mon], lt->tm_year + 1900,
  387.             lt->tm_hour, lt->tm_min, lt->tm_sec,
  388. #ifdef USG
  389.             tzname[lt->tm_isdst ? 1 : 0]
  390. #else
  391.             lt->tm_zone
  392. #endif
  393.             );
  394. }
  395.  
  396. /*----------------------------------------------------------------------
  397.  * Write a concluding marker to the given logfile.
  398.  * This marker separates instances of Deliver at recursion level zero.
  399.  */
  400.  
  401. logdone(fp)
  402. FILE    *fp;
  403. {
  404.     if (rec_level == 0)
  405.         (void) fputs("===========================\n\n", fp);
  406. }
  407.